ECharts(Enterprise Charts)是一个基于JavaScript的开源数据可视化图表库,最初由百度开发,现由Apache软件基金会维护,它功能强大、交互性强,可用于Web页面上的数据可视化,实现折线图、柱状图、饼图、散点图、地图等交互图表的制作。
在R语言中,有很多包可以制作ECharts,其中echarty使用原生API,命令简洁,可实现ECharts的大部分功能。
使用echarty绘图时,对于基础图表,如折线图、柱状图等,可参考ECharts案例,将其中的JS代码改写为R代码即可,下面是一个简要的例子。
参考ECharts案例:https://echarts.apache.org/examples/zh/editor.html?c=line-stack
# 加载包
library(echarty)
# 画图
ec.init(
title = list(text = "Stacked Line"),
tooltip = list(trigger = "axis"),
legend = list(data = c("Email", "Union Ads", "Video Ads", "Direct", "Search Engine")),
grid = list(left = "3%", right = "4%", bottom = "3%", containLabel = TRUE),
toolbox = list(
feature = list(
saveAsImage = list()
)
),
xAxis = list(
type = "category",
boundaryGap = FALSE,
data = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
),
yAxis = list(type = "value"),
series = list(
list(
name = "Email",
type = "line",
stack = "Total",
data = c(120, 132, 101, 134, 90, 230, 210)
),
list(
name = "Union Ads",
type = "line",
stack = "Total",
data = c(220, 182, 191, 234, 290, 330, 310)
),
list(
name = "Video Ads",
type = "line",
stack = "Total",
data = c(150, 232, 201, 154, 190, 330, 410)
),
list(
name = "Direct",
type = "line",
stack = "Total",
data = c(320, 332, 301, 334, 390, 330, 320)
),
list(
name = "Search Engine",
type = "line",
stack = "Total",
data = c(820, 932, 901, 934, 1290, 1330, 1320)
)
)
)
对比可以发现,使用echarty绘图,只要把ECharts的JS改写成R中的list就行了,非常简单:
然而,当绘制地图时,情况就有些复杂了。多次尝试后,我总结了以下内容,可以便捷地用echarty绘制地图。
需要注意的:
这里按地图类别自定义了几个绘图函数(注意,函数参数仅为方便本次画图,实际使用时,更多细节需在函数内部调整。函数参数maplevel并不严格,仅是非中国省级地图时,值不能为china,否则echarty包会在地图上额外添加一个南海诸岛图):
mapplot_fill_valuemapplot_fill_classmapplot_point_valuemapplot_point_classecharty绘制地图需要geojson/json地图文件,两者只要是内部没错误,扩展名可以直接更改。
在绘制地图即绘图函数series中的type = "map"时,可使用ec.data函数将data.frame数据转list数据,此时需要指定format参数为names,并且绘图数据的列名必须为name和value。
绘图数据中的name列,其值决于geojson中的name的值,读取geojson文件后可通过sapply(map$features, function(feature) feature$properties$name)查看。
如需修改地图上name标签的显示位置,可以在geojson文件中,name后添加如下属性以自定义显示位置:“cp”:[114.505,22.050]。
必需要注册地图,然后它才能显示出来。
如果geojson文件过大,渲染地图会非常耗时,此时如果对精度要求不高,可以使用下面的mapshaper简化地图。
文中所用的数据,见github。注意中国-省级地图以及中国-市级地图都已经过多边形简化,并不精确。
geojson地图文件的相关连接
在线工具mapshaper,可用于地图精简、编辑:https://mapshaper.org/
在线工具Mapbox geojson,可进行地图编辑:https://geojson.io/
开源地信软件QGis,可用于geojson缩放,下载地址:https://download.osgeo.org/qgis/win64/
geojson地图资源:
注意:GeoJson下载的topojson地图,可以用mapshaper将其转换为geojson/json使用
以下是地图绘制函数的定义,以及三个绘图示例
mapplot_fill_value <- function(df_value, jsonmap,
maplevel = "china",
showlabel = T,
showcolorbar = T){
# 画地图函数
ecmap <- ec.init(
# 数据序列
series = list(
list(
type = "map",
map = maplevel,
label = list(
show = showlabel,
formatter = htmlwidgets::JS("
function(params) {
if (params.name == '南海诸岛' || params.name == '十段线') {
return ''; // 返回空字符串,隐藏这些标签
}
return params.name;
}
")
),
data = ec.data(df_value, format = "names")
)
),
# 鼠标悬停提示标签样式
tooltip = list(
trigger = "item",
formatter = htmlwidgets::JS("
function(params) {
return params.name + ': ' + params.value + '';
}
")
),
# 工具条(数据、还原、下载)
toolbox = list(
show = TRUE,
orient = "vertical", #垂直
left = "left", #位置在左侧
top = "45%", #距离顶部的距离
feature = list(
dataView = list(readOnly = FALSE),
restore = list(),
saveAsImage = list()
)
),
# 图例(colorbar)
visualMap = list(
show = showcolorbar,
min = min(df_value$value),
max = max(df_value$value),
# inRange = list(color = c("#ECF9FF", "#5470C6")), #调整颜色范围
inRange = list(color = c("lightskyblue", "yellow", "orangered")),
orient = "vertical", #垂直显示
right = "100px", #设置右侧的偏移
top = "45%", #设置距离顶部的偏移
itemWidth = 20, #设置每个项的宽度
itemHeight = 250, #设置每个项的高度
calculable = TRUE #可计算范围
)
)
# 注册并返回地图
ecmap$x$registerMap <- list(list(mapName=maplevel, geoJSON=jsonmap))
return(ecmap)
}
mapplot_fill_class <- function(df_class, jsonmap,
maplevel = "china",
showlabel = TRUE,
showlegend = TRUE,
class_order = NULL) {
# 使用用户自定义顺序,或默认顺序,注意默认顺序legend显示由低到高,所以需要rev()
if (is.null(class_order)) {
class_names <- unique(df_class$class) %>% rev()
} else {
class_names <- class_order %>% rev()
}
# 将分类转为数值ID(根据顺序)
df_class$cat_id <- match(df_class$class, class_names)
# 设置颜色
# colors <- rainbow(6) #特定数据绘图,可以在此自定义颜色
colors <- scales::hue_pal()(length(class_names))
# 给定显示颜色
visual_pieces <- lapply(seq_along(class_names), function(i) {
list(
value = i,
label = class_names[i],
color = colors[i]
)
})
# 地图数据
data_map <- df_class %>% dplyr::transmute(name = name, value = cat_id, class = class)
# 绘图对象
ecmap <- ec.init(
# 数据序列
series = list(
list(
# name = "地区分类",
type = "map",
map = maplevel,
roam = TRUE,
roam = TRUE, #支持缩放和平移
scaleLimit = list(
min = 0.5, #最小缩放比例
max = 2 #最大缩放比例
),
label = list(
show = showlabel,
formatter = htmlwidgets::JS("
function(params) {
if (params.name == '南海诸岛' || params.name == '十段线') {
return '';
}
return params.name;
}
")
),
data = ec.data(data_map, format = "names")
)
),
# 鼠标悬停
tooltip = list(
trigger = "item",
formatter = htmlwidgets::JS("
function(params) {
return params.name + '(' + params.data.class + ')';
}
")
),
# 图例
visualMap = list(
type = "piecewise",
show = showlegend,
pieces = visual_pieces,
orient = "vertical",
left = "right",
top = "center",
itemWidth = 20,
itemHeight = 20
),
# 工具条
toolbox = list(
show = TRUE,
orient = "vertical", #垂直
left = "left", #位置在左侧
top = "45%", #距离顶部的距离
feature = list(
saveAsImage = list(),
restore = list()
)
)
)
# 注册并返回地图
ecmap$x$registerMap <- list(list(mapName = maplevel, geoJSON = jsonmap))
return(ecmap)
}
mapplot_point_value <- function(df_value, jsonmap,
maplevel = "china",
showcolorbar = TRUE,
dpointsize = TRUE){
# 散点数据结构:[lon, lat, value]
scatter_data <- lapply(seq_len(nrow(df_value)), function(i) {
list(
name = df_value$name[i],
value = c(df_value$lon[i], df_value$lat[i], df_value$value[i])
)
})
# 散点动态大小的js代码
minVal <- min(df_value$value)
maxVal <- max(df_value$value)
if(dpointsize){
symbolSizeJS <- sprintf(
"function(val){
var minVal = %f;
var maxVal = %f;
var minSize = 8; //最小点大小
var maxSize = 18; //最大点大小
var size = minSize + (val[2] - minVal) / (maxVal - minVal) * (maxSize - minSize);
return size;
}",
minVal, maxVal
)
} else{
symbolSizeJS <- "function(val){ return 8; }"
}
# 画图
ecmap <- ec.init(
# 地图背景
geo = list(
map = maplevel,
roam = TRUE, #支持缩放和平移
scaleLimit = list(
min = 0.5, #最小缩放比例
max = 2 #最大缩放比例
),
itemStyle = list(
areaColor = "#f5f5f5",
borderColor = "#999"
),
emphasis = list( #禁止悬停强调
itemStyle = list(
areaColor = "#f5f5f5", #鼠标悬停时区域颜色不变
borderColor = "#999" #边界颜色不变
),
label = list(
show = FALSE #禁止显示悬停label
)
)
# tooltip = list(show = FALSE) #禁止悬停效果,全局的,禁后散点的悬停也没有了
),
# 数据序列
series = list(
list(
type = "scatter",
coordinateSystem = "geo",
data = scatter_data,
symbolSize = htmlwidgets::JS(symbolSizeJS), #散点大小
label = list(
show = TRUE,
position = "right",
formatter = "{b}" #显示城市名称
),
itemStyle = list(
opacity = 0.9,
borderColor = "black",
borderWidth = 1
)
)
),
# 鼠标悬停效果
tooltip = list(
trigger = "item",
formatter = htmlwidgets::JS("
function(params) {
return params.name + ': ' + params.value[2];
}
")
),
# 图例
visualMap = list(
show = showcolorbar,
min = min(df_value$value),
max = max(df_value$value),
calculable = TRUE,
inRange = list(color = c("lightskyblue", "yellow", "orangered")),
orient = "vertical",
right = "20px",
top = "center"
),
# 工具条
toolbox = list(
show = TRUE,
orient = "vertical", #垂直
left = "left", #位置在左侧
top = "45%", #距离顶部的距离
feature = list(
dataView = list(readOnly = FALSE),
restore = list(),
saveAsImage = list()
)
)
)
# 注册并返回地图
ecmap$x$registerMap <- list(list(mapName = maplevel, geoJSON = jsonmap))
return(ecmap)
}
mapplot_point_class <- function(df_class, jsonmap,
maplevel = "china",
showlabel = TRUE,
class_order = NULL) {
# 设定分类顺序
if (is.null(class_order)) {
class_names <- unique(df_class$class)
} else {
class_names <- class_order
}
# 设置颜色
# colors <- rainbow(6) #特定数据绘图,可以在此自定义颜色
colors <- scales::hue_pal()(length(class_names))
# 每类一个 scatter series
series_list <- lapply(seq_along(class_names), function(i) {
cname <- class_names[i]
cdata <- df_class[df_class$class == cname, ]
scatter_data <- lapply(seq_len(nrow(cdata)), function(j) {
list(
name = cdata$name[j],
value = c(cdata$lon[j], cdata$lat[j], cname),
class = cname
)
})
list(
name = cname, #影响legend的label显示顺序
type = "scatter",
coordinateSystem = "geo",
data = scatter_data,
symbolSize = 12,
label = list(
show = showlabel,
position = "right",
formatter = "{b}"
),
itemStyle = list(
color = colors[i],
borderColor = "black",
borderWidth = 0.5,
opacity = 0.9
)
)
})
# 绘图
ecmap <- ec.init(
# 地图背景
geo = list(
map = maplevel,
roam = TRUE, #支持缩放和平移
scaleLimit = list(
min = 0.5, #最小缩放比例
max = 2 #最大缩放比例
),
itemStyle = list(
areaColor = "#f5f5f5",
borderColor = "#999"
),
emphasis = list(
itemStyle = list(
areaColor = "#f5f5f5",
borderColor = "#999"
),
label = list(show = FALSE)
)
),
# 数据序列
series = series_list,
# 图例
legend = list(
type = "scroll",
orient = "vertical",
left = "right",
top = "center",
data = class_names, #明确指定legend顺序
itemWidth = 12,
itemHeight = 12,
itemStyle = list(
borderColor = "black",
borderWidth = 0.5,
opacity = 0.9
)
),
# 鼠标悬停
tooltip = list(
trigger = "item",
formatter = htmlwidgets::JS("
function(params) {
return params.name + '(' + params.data.class + ')';
}
")
),
# 工具条
toolbox = list(
show = TRUE,
orient = "vertical", #垂直
left = "left", #位置在左侧
top = "45%", #距离顶部的距离
feature = list(
saveAsImage = list(),
restore = list()
)
)
)
# 注册并返回地图
ecmap$x$registerMap <- list(list(mapName = maplevel, geoJSON = jsonmap))
return(ecmap)
}
# 加载包
library(echarty)
library(jsonlite)
library(magrittr)
# 读取地图
map_world_county <- read_json("world_country.json")
# 识别name标签
country_name <- sapply(map_world_county$features, function(feature) feature$properties$name) %>%
Filter(nzchar, .)
# 随机数据
df_world <- data.frame(name = country_name,
value = runif(length(country_name), 0, 100) %>% round(2))
# 执行画图
mapplot_fill_value(df_world, map_world_county,
maplevel = "world",
showlabel = F,
showcolorbar = F)
# 加载包
library(echarty)
library(jsonlite)
# 示例数据
df_china <- data.frame(name = c('安徽', '澳门', '北京', '福建', '甘肃', '广东',
'广西', '贵州', '海南', '河北', '河南', '黑龙江',
'湖北', '湖南', '吉林', '江苏', '江西', '辽宁',
'内蒙古', '宁夏', '青海', '山东', '山西', '陕西',
'上海', '四川', '台湾', '天津', '西藏', '香港',
'新疆', '云南', '浙江', '重庆'),
value = c(2727, 159, 6397, 2819, 1257, 3332, 1548, 1557,
124, 1923, 3641, 2896, 8236, 8640, 3153, 2255,
3954, 4416, 421, 417, 603, 825, 1228, 1397, 3748,
587, 62, 2289, 239, 361, 662, 5215, 108, 492))
# 中国省级地图
map_china_province <- read_json("china_province_simplified.json")
# 执行画图
mapplot_fill_value(df_china, map_china_province,
maplevel = "china")
分类显示中国经济地理区划
# 加载包
library(echarty)
library(jsonlite)
library(magrittr)
# library(dplyr)
# 示例分类数据(中国自然资源部版划分法)
df_class <- data.frame(
name = c('北京', '天津', '河北', '山东', '山西', '内蒙古', #华北6个
'辽宁', '吉林', '黑龙江', #东北3个
'上海', '江苏', '浙江', '安徽', #华东4个
'广东', '广西', '福建', '海南', #华南4个
'湖北', '湖南', '河南', '江西', #华中4个
'重庆', '四川', '贵州', '云南', '西藏', #西南5个
'陕西', '甘肃', '青海', '宁夏', '新疆', #西北5个
'香港', '澳门', '台湾'), #港澳台3个
class = c('华北', '华北', '华北', '华北', '华北', '华北',
'东北', '东北', '东北',
'华东', '华东', '华东', '华东',
'华南', '华南', '华南', '华南',
'华中', '华中', '华中', '华中',
'西南', '西南', '西南', '西南', '西南',
'西北', '西北', '西北', '西北', '西北',
'港澳台', '港澳台', '港澳台')
)
my_order <- c("华北", "东北","华中","华东", "华南", "西北", "西南", "港澳台")
# 中国省级地图
map_china_province <- read_json("china_province_simplified.json")
# 执行画图
mapplot_fill_class(df_class, map_china_province,
showlabel = F,
showlegend = T,
class_order = my_order)
分类显示中国地市级经济发展水平,其中,城市分级来自《2025新一线城市魅力排行榜》,而地图数据中部分城市区划变更未更新,与排行榜不吻合,其中,所有在排行榜中的城市,均已标记在地图上,但地图上某些城市未出现在排行榜上。
# 加载包
library(echarty)
library(jsonlite)
library(magrittr)
# library(dplyr)
# 读取数据
dat <- read.csv("city_tier.csv")
# 中国市级地图
map_china_city <- read_json("china_city_simplified.json")
# 生成数据
dat_city_tier <- data.frame(name = dat$name_area, class = dat$type)
tierorder <- c("一线城市", "新一线城市", "二线城市", "三线城市", "四线城市", "五线城市")
# 执行画图
mapplot_fill_class(dat_city_tier, map_china_city,
maplevel = "others", #这里如果是china则会有额外的南海诸岛图
showlabel = F,
showlegend = T,
class_order = tierorder)
在地图上添加数据点,其中点展示数值型数据,地图仅作为背景。
# 加载包
library(echarty)
library(jsonlite)
library(magrittr)
# 读取城市坐标数据
data <- read.csv("city_tier.csv")
# 读取地图
map_gd_province <- read_json("guangdong_province.geojson")
# 生成随机绘图数据
dat_city_value <- data[data$province=="广东省",]
dat_city_value$value <- runif(nrow(dat_city_value),0,100) %>% round(2)
# 执行画图
mapplot_point_value(dat_city_value, map_gd_province,
maplevel = "guangdong_province",
showcolorbar = T,
dpointsize = F)
在地图上添加数据点,其中点展示分类型数据,地图仅作为背景。此图同样展示了《2025新一线城市魅力排行榜》中的城市等级划分情况。
# 加载包
library(echarty)
library(jsonlite)
library(magrittr)
# library(dplyr)
# 读取城市发展数据
dat <- read.csv("city_tier.csv", encoding = "UTF-8")
# 中国省级地图
map_china_province <- read_json("china_province_simplified.json")
# 生成地图数据
dat_city_tier <- data.frame(name = dat$name,
lon = dat$lon,
lat = dat$lat,
class = dat$type)
tierorder <- c("一线城市", "新一线城市", "二线城市", "三线城市", "四线城市", "五线城市")
# 执行画图
mapplot_point_class(dat_city_tier, map_china_province,
maplevel = "china_province",
showlabel = F,
class_order = tierorder)